#include "header.h"
#include "config.h"
/*63位
‌Wi-Fi密码的最大长度通常为63位‌，具体限制可能因路由器型号和加密方式（如WPA2-PSK）而异。‌‌
32个ASCII字符
‌WiFi名称（SSID）的最长限制为32个ASCII字符‌，这是由IEEE 802.11无线局域网标准定义的通用规范。
加上前后感叹句，所以收一个就可以了‌‌
*/
//宏函数，清空一个char数组arr
#define CLEAR_ARRAY_WITH_LOOP(arr) do { \
    size_t _count = sizeof(arr) / sizeof((arr)[0]); \
    for (size_t _i = 0; _i < _count; _i++) { \
        (arr)[_i] = 0; \
    } \
} while (0)
QueueHandle_t queueESP01;                  // 用来接受ESP01发送消息的消息队列
QueueHandle_t queueADC;					   //用于接收传感器消息
SemaphoreHandle_t  xBinarySemaphoreHC01toESP01;// 等待wifi账号密码获取读取信号量的初始化
SemaphoreHandle_t xBinarySemaphoreESP01toADC; // 等待TCP连接成功，ADC才可以开始上传的信号量
SemaphoreHandle_t xBinarySemaphoreDisconnect;//按键断开TCP连接
EventGroupHandle_t
xEventGroupNetStatus;                //网络状态的时间标志组，用来标记wifi和TCP的连接状态
int ESP01work = 1; //ESP01发送数据的标志位，
int Netstatus = 1;//标记网络状态，为1则直接传感器发送到ESP01，否则存入W25Q64
const int address = 0x0800F000;//密码存储的位置
int W25Q64WriteAddress = 0x0000000; //记录W25Q64读写地址
int W25Q64DataNums = 0; //记录W25Q64中有多少数据

int GetFromQueue(QueueHandle_t queue, char buf[]);

TimerHandle_t xLongPressTimer;// 声明长按重置软件定时器句柄,定时3秒

char wifiname[32] = {0};
char wifipassword[64] = {0};
// 软件定时器回调函数
void vLongPressCallback(TimerHandle_t xTimer) {
    GPIO_WriteBit(GPIOA, GPIO_Pin_11,
                  (BitAction)(1 ^ GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_11)));
    printf2("vLongPressCallback\n");
    printf2("wifi erase\n");
    char buf[100] = {0};
    ESP01SC_disconnectTCP(buf);
    GetCode(buf);
    AnalysisCode(buf, wifiname, wifipassword);
    ESP01SC_connectWIFI(buf, wifiname, wifipassword);
    ESP01SC_connectTCP(buf, SERVERIP, SERVERPORT);
    //   LED_Reverset(GPIO_Pin_11);
}

void NetChecktask(void *arg) {
    printf2("Nettask start\n");

    while (1) {
        EventBits_t uxBits = xEventGroupWaitBits(xEventGroupNetStatus, WIFI_DISCONNECT | TCP_DISCONNECT, pdTRUE, pdFALSE,
                             portMAX_DELAY);
        char buf[200] = {0};
        int ret;
        if (uxBits & WIFI_DISCONNECT) {
            printf2("检测到WIFI_DISCONNECT事件 \r\n");
            for (int i = 0; i < 3; i++) {
                ret = ESP01SC_connectWIFI(buf, wifiname, wifipassword);
                printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
                if (ret > 0) {
                    break;
                }
            }
        }
        if (uxBits & TCP_DISCONNECT) {
            printf2("检测到TCP_DISCONNECT事件 \r\n");
            for (int i = 0; i < 3; i++) {
                ret = ESP01SC_connectTCP(buf, SERVERIP, SERVERPORT);
                printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
                if (ret > 0) {
                    break;
                }
            }
        }
    }
}

void ESP01task(void *arg) {
    // 用于和ESP01通信的任务
    printf2("ESP01task start\n");
    Checkcode();//第一次使用，配置网络


    if (xSemaphoreTake(xBinarySemaphoreHC01toESP01, portMAX_DELAY) == pdPASS) {
        printf2("WiFi get \n");
    }

    OLED_ShowString(1, 1, "Get Information From Bluetooth");
    printf2("line:%d\n", __LINE__);
    char buf[200] = {0};
    int ret = SendCommandToESP01S(buf, "AT\r\n");
    printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
    CLEAR_ARRAY_WITH_LOOP(buf);

    ret = SendCommandToESP01S(buf, "AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", wifiname, wifipassword); //发送密码
    printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
    CLEAR_ARRAY_WITH_LOOP(buf);

    OLED_Clear();
    OLED_ShowString(1, 1, "WIFI CONNECTED");

    ret = SendCommandToESP01S(buf, "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n", SERVERIP, SERVERPORT); //发送IP和端口
    printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
    CLEAR_ARRAY_WITH_LOOP(buf);

    OLED_Clear();
    OLED_ShowString(1, 1, "TCP CONNECTED");

    ret = SendCommandToESP01S(buf, "AT+CIPMODE=1\r\n");
    printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
    CLEAR_ARRAY_WITH_LOOP(buf);

    ret = SendCommandToESP01S(buf, "AT+CIPSEND\r\n");
    printf2("line:%d ret:%d buf:\n%s\n", __LINE__, ret, buf);
    CLEAR_ARRAY_WITH_LOOP(buf);	

    xSemaphoreGive(xBinarySemaphoreESP01toADC);//让ADC开始工作

    printf2("line:%d ESP01work:%d\n", __LINE__, ESP01work);

    Netstatus = 1;

    while (1) {
        if (ESP01work == 1) {//如果有网络，则上传数据20
            char msg[17] = {0};

            if (W25Q64DataNums != 0) { //如果有未发送数据，先发送未发送的数据
                int W25Q64ReadAddress = 0x0000000;

                for (int i = 0; i < W25Q64DataNums; i++) {
                    W25Q64_ReadData(W25Q64ReadAddress, (uint8_t*)msg, sizeof(msg) -1); //读取对应长度的数据
                    W25Q64ReadAddress += sizeof(msg) -1;
                    SendMessageToESP01S(msg);
                    printf2("line:%d,msg:---%s---\n", __LINE__, msg);
                    W25Q64DataNums--;
                }

                W25Q64DataNums = 0;
                W25Q64WriteAddress = 0x0000000;
                W25Q64_SectorErase(0x0000000);
                W25Q64_SectorErase(0x0001000);
            }

            xQueueReceive(queueADC, msg, portMAX_DELAY);
            msg[sizeof(msg) -1] = '\0';
            SendMessageToESP01S(msg);
            printf2("line:%d,msg:---%s---\n", __LINE__, msg);
        }
    }
}

void ADCtask(void *arg) {
    printf2("task3 start\n");

    if (xSemaphoreTake(xBinarySemaphoreESP01toADC, portMAX_DELAY) == pdPASS) {
        printf2("ADCtask get xBinarySemaphoreESP01toADC \r\n");
    }

    uint32_t AD[4];
    uint8_t AD_Channel[4] = {ADC_Channel_4, ADC_Channel_5, ADC_Channel_6, ADC_Channel_7};
    OLED_Clear();
    OLED_ShowString(1, 1, "AD0:");
    OLED_ShowString(2, 1, "AD1:");
    OLED_ShowString(3, 1, "AD2:");
    OLED_ShowString(4, 1, "AD3:");

    while (1) {
        char strs[17] = {0};

        for (uint8_t i = 0; i < 4; i++) {
            AD[i] = AD_GetValue(AD_Channel[i]);
            OLED_ShowSignedNum(i + 1, 5, AD[i], 4);
            // 安全格式化，避免缓冲区溢出
            snprintf(strs + 4 * i, 5, "%04u", AD[i]); //四位数字，不足补0
        }

        if (Netstatus == 1) {//如果网络状态良好，则发送数据
            xQueueSend(queueADC, strs, portMAX_DELAY);
            printf2("line:%d,msg,send:---%s---\n", __LINE__, strs);
        } else {
            W25Q64_PageProgram(W25Q64WriteAddress, (uint8_t*)strs, sizeof(strs) -1); //结束符不写入
            W25Q64WriteAddress += sizeof(strs) -1; //读写地址便宜
            W25Q64DataNums++;
            printf2("line:%d,msg,spi:---%s---\n", __LINE__, strs);;
        }

        vTaskDelay(500);
        LED_Reverset(GPIO_Pin_8);
        vTaskDelay(500);
        LED_Reverset(GPIO_Pin_8);
        vTaskDelay(4000);//5秒采集一次数据
    }
}

void NetStatustask(void *arg) {
    printf2("task4 start\n");

    while (1) {
        xSemaphoreTake(xBinarySemaphoreDisconnect, portMAX_DELAY);
        char buf[200] = {0};
        int ret;

        if (Netstatus == 0) {
            ESP01SC_connectTCP(buf, SERVERIP, SERVERPORT);
            Netstatus = 1;
        } else {
            ESP01SC_disconnectTCP(buf);
            Netstatus = 0;
        }
    }
}

int main(void) {
    Delay_Init(); // 初始化延时时钟

    /*NVIC中断分组*/
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);		//配置NVIC为分组4
    xBinarySemaphoreHC01toESP01 = xSemaphoreCreateBinary(); // 等待wifi账号密码获取读取信号量的初始化
    xBinarySemaphoreESP01toADC = xSemaphoreCreateBinary(); // 等待TCP连接成功，开始进行ADC转化
    xBinarySemaphoreDisconnect = xSemaphoreCreateBinary(); // 用于控制断开TPC连接
    queueESP01 = xQueueCreate(100, 1);//用于接收ESP01串口消息的消息队列
    queueADC = xQueueCreate(1, 16); //用于接收传感器消息数字大小为4*4 位数字，转为字符串
    xEventGroupNetStatus = xEventGroupCreate(); //用于标记网络状态的标志组

    OLED_Init();   // 初始化LED
    OLED_ShowString(1, 1, " System Loading...");//显示系统加载中
    USART2_Init(); // 初始化USART2串口
    ESP01S_Init(); // 初始化ESP01S串口(USART1)
    HC05_Init();   ////初始化HC05串口(USART3)
    Key_Init();//各种按键初始化
    LED_Init();//初始化LED
    AD_Init();//初始化ADC

    xLongPressTimer = xTimerCreate("LongPressTimer", 3000, pdFALSE, NULL, vLongPressCallback);
    printf2("line:%d\n", __LINE__);
    Delay_ms(1000);
    xTaskCreate(NetChecktask, "NetCheckTask", configMINIMAL_STACK_SIZE * 2, NULL, 2, NULL);
    xTaskCreate(ESP01task, "ESP01Task", configMINIMAL_STACK_SIZE * 4, NULL, 2, NULL);
    xTaskCreate(ADCtask, "ADCTask", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    xTaskCreate(NetStatustask, "NetStatusTask", configMINIMAL_STACK_SIZE * 4, NULL, 3, NULL);
    OLED_ShowString(1, 1, "System Runing");
    vTaskStartScheduler();

    while (1) {
    }
}

//串口中断,用于接收数据
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {
        char data = (uint8_t)USART_ReceiveData(USART1);
        BaseType_t stat = pdTRUE;
        xQueueSendFromISR(queueESP01, &data, &stat);
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

// 外部中断服务函数，用于检测PA0停止上传按钮
void EXTI0_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) == SET) {//A0为下降沿触发
        // ESP01work = 0; //ESP01发送数据的标志位，
        //  Netstatus = 0;//网络断开标志
        BaseType_t stat = pdTRUE;
        xSemaphoreGiveFromISR(xBinarySemaphoreDisconnect, &stat);
        GPIO_ResetBits(GPIOC, GPIO_Pin_13);
        EXTI_ClearITPendingBit(EXTI_Line0);    // 清除 EXTI0 中断标志
    }
}


// 外部中断服务函数，用于检测PA12复位系统按钮
void EXTI15_10_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line12) != RESET) {
        Delay_ms(20);

        while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_SET) {} //消抖

        if (GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN) == RESET) {
            // 按下：启动定时器
            xTimerStartFromISR(xLongPressTimer, 0);
        } else {
            // 释放：停止定时器
            xTimerStopFromISR(xLongPressTimer, 0);
        }

        EXTI_ClearITPendingBit(EXTI_Line12);
    }
}

// 比如WIFI已经连接
// 比如数据发送条目数

//从消息队列queue中读取字符，存储在buf中，读到结束符flag位置，
int GetFromQueue(QueueHandle_t queue, char buf[]) {
    int count = 0;

    while (1) {
        xQueueReceive(queue, buf + count, portMAX_DELAY);
        count++;

        if (count >= 2 && buf[count - 2] == 'O' && buf[count - 1] == 'K') {
            xQueueReset(queue);
            break;
        }

        if (count >= 6 && buf[count - 6] == 'F' && buf[count - 5] == 'A' && buf[count - 4] == 'I' && buf[count - 3] == 'L') {
            xQueueReset(queue);
            return WIFIFAIL;//返回FAIL -1
        }

        if (count >= 8 && buf[count - 7] == 'E' && buf[count - 6] == 'R' && buf[count - 5] == 'R' && buf[count - 4] == 'O'
                && buf[count - 3] == 'R') {
            xQueueReset(queue);
            return WIFIERROR;//返回ERROR -2
        }

        if (count > 1 && buf[count - 1] == '!' && buf[0] == '!') {
            break;//读取蓝牙
        }

        if (count == 100) {//防止读到奇怪的数据
            break;
        }
    }

    return count;  // 返回实际读取的元素数量
}

